3.2.9 Promise
目前实现按照正常的思路走下来的,可能会存在些问题
实现一个 promise
1.初步构建
Promise 的参数是函数 fn,
把内部定义 resolve 方法作为参数传到 fn 中,调用 fn。
当异步操作成功后会调用 resolve 方法,
然后就会执行 then 中注册的回调函数。
function Promise(fn){
//需要一个成功时的回调
var doneCallback;
//一个实例的方法,用来注册异步事件
this.then = function(done){
doneCallback = done;
}
function resolve(){
doneCallback();
}
fn(resolve);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
2.加入链式支持
下面加入链式,成功回调的方法就得变成数组才能存储。同时我们给 resolve 方法添加参数,这样就不会输出 undefined。
下面加入链式,成功回调的方法就得变成数组才能存储
function Promise(fn){
//需要成功以及成功时的回调
var doneList = [];
//一个实例的方法,用来注册异步事件
this.then = function(done ,fail){
doneList.push(done);
return this;
}
function resolve(){
doneList.forEach(function(fulfill){
fulfill();
});
}
fn(resolve);
}
这里promise里面如果是同步的函数的话,doneList里面还是空的,所以可以加个setTimeout来将这个放到js的最后执行。
这里主要是参照了promiseA+的规范,就像这样
function resolve(){
setTimeout(function(){
doneList.forEach(function(fulfill){
fulfill();
});
},0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
3.引入状态
这时如果promise已经执行完了,我们再给promise注册then方法就怎么都不会执行了,这个不符合预期,所以才会加入状态这种东西。更新过的代码如下
function Promise(fn){
//需要成功以及成功时的回调
var state = 'pending';
var doneList = [];
//一个实例的方法,用来注册异步事件
this.then = function(done){
switch(state){
case "pending":
doneList.push(done);
return this;
break;
case 'fulfilled':
done();
return this;
break;
}
}
function resolve(){
state = "fulfilled";
setTimeout(function(){
doneList.forEach(function(fulfill){
fulfill();
});
},0);
}
fn(resolve);
}
加上结果的传递:
function resolve(newValue){
state = "fulfilled";
var value = newValue;
setTimeout(function(){
doneList.forEach(function(fulfill){
value = fulfill(value);
});
},0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
4.支持串行
function Promise(fn){
//需要成功以及成功时的回调
var state = 'pending';
var doneList = [];
this.then = function(done){
switch(state){
case "pending":
doneList.push(done);
return this;
break;
case 'fulfilled':
done();
return this;
break;
}
}
function resolve(newValue){
state = "fulfilled";
setTimeout(function(){
var value = newValue;
//执行resolve时,我们会尝试将doneList数组中的值都执行一遍
//当遇到正常的回调函数的时候,就执行回调函数
//当遇到一个新的promise的时候,就将原doneList数组里的回调函数推入新的promise的doneList,以达到循环的目的
for (var i = 0;i<doneList.length;i++){
var temp = doneList[i](value)
if(temp instanceof Promise){
var newP = temp;
for(i++;i<doneList.length;i++){
newP.then(doneList[i]);
}
}else{
value = temp;
}
}
},0);
}
fn(resolve);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
5.加入reject
function Promise(fn){
var state = 'pending';
var doneList = [];
var failList= [];
this.then = function(done ,fail){
switch(state){
case "pending":
doneList.push(done);
//每次如果没有推入fail方法,我也会推入一个null来占位
failList.push(fail || null);
return this;
break;
case 'fulfilled':
done();
return this;
break;
case 'rejected':
fail();
return this;
break;
}
}
function resolve(newValue){
state = "fulfilled";
setTimeout(function(){
var value = newValue;
for (var i = 0;i<doneList.length;i++){
var temp = doneList[i](value);
if(temp instanceof Promise){
var newP = temp;
for(i++;i<doneList.length;i++){
newP.then(doneList[i],failList[i]);
}
}else{
value = temp;
}
}
},0);
}
function reject(newValue){
state = "rejected";
setTimeout(function(){
var value = newValue;
var tempRe = failList[0](value);
//如果reject里面传入了一个promise,那么执行完此次的fail之后,将剩余的done和fail传入新的promise中
if(tempRe instanceof Promise){
var newP = tempRe;
for(i=1;i<doneList.length;i++){
newP.then(doneList[i],failList[i]);
}
}else{
//如果不是promise,执行完当前的fail之后,继续执行doneList
value = tempRe;
doneList.shift();
failList.shift();
resolve(value);
}
},0);
}
fn(resolve,reject);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62